#include"head.h"
#include"common.h"
void printLine(void){
	printf("----------------------------------------------------------------------------------------------------------------------------------\n");
}
int IPstr2IPint(const char *ipStr, unsigned int *ip, unsigned int *mask){
	// init
	int p = -1, count = 0;
	unsigned int len = 0, tmp = 0, r_mask = 0, r_ip = 0,i;
	for(i = 0; i < strlen(ipStr); i++){
		if(!(ipStr[i]>='0' && ipStr[i]<='9') && ipStr[i]!='.' && ipStr[i]!='/') {
			return -1;
		}
	}
	// 获取掩码
	for(i = 0; i < strlen(ipStr); i++){
        if(p != -1){
            len *= 10;
            len += ipStr[i] - '0';
        }
        else if(ipStr[i] == '/')
            p = i;
    }
	if(len > 32 || (p>=0 && p<7)) {
		return -1;
	}
    if(p != -1){
        if(len)
            r_mask = 0xFFFFFFFF << (32 - len);
    }
    else r_mask = 0xFFFFFFFF;
	// 获取IP
    for(i = 0; i < (p>=0 ? p : strlen(ipStr)); i++){
        if(ipStr[i] == '.'){
            r_ip = r_ip | (tmp << (8 * (3 - count)));
            tmp = 0;
            count++;
            continue;
        }
        tmp *= 10;
        tmp += ipStr[i] - '0';
		if(tmp>256 || count>3)
			return -2;
    }
    r_ip = r_ip | tmp;
	*ip = r_ip;
	*mask = r_mask;
    return 0;
}

int IPint2IPstr(unsigned int ip, unsigned int mask, char *ipStr) {
    unsigned int i,ips[4],maskNum = 32;
    if(ipStr == NULL) {
        return -1;
    }
	if(mask == 0)
		maskNum = 0;
	else {
		while((mask & 1u) == 0) {
                	maskNum--;
                	mask >>= 1;
        	}
	}
    for(i=0;i<4;i++) {
        ips[i] = ((ip >> ((3-i)*8)) & 0xFFU);
    }
	sprintf(ipStr, "%u.%u.%u.%u/%u", ips[0], ips[1], ips[2], ips[3], maskNum);
	return 0;
}
int IPint2IPstrNoMask(unsigned int ip, char *ipStr) {
    unsigned int i,ips[4];
    if(ipStr == NULL) {
        return -1;
    }
    for(i=0;i<4;i++) {
        ips[i] = ((ip >> ((3-i)*8)) & 0xFFU);
    }
	sprintf(ipStr, "%u.%u.%u.%u", ips[0], ips[1], ips[2], ips[3]);
	return 0;
}
int IPint2IPstrWithPort(unsigned int ip, unsigned short port, char *ipStr) {
    if(port == 0) {
        return IPint2IPstrNoMask(ip, ipStr);
    }
    unsigned int i,ips[4];
    if(ipStr == NULL) {
        return -1;
    }
    for(i=0;i<4;i++) {
        ips[i] = ((ip >> ((3-i)*8)) & 0xFFU);
    }
	sprintf(ipStr, "%u.%u.%u.%u:%u", ips[0], ips[1], ips[2], ips[3], port);
	return 0;
}
struct KernelResponse addFilterRule(char *name,char *sip,char *dip,unsigned int sport,unsigned int dport,u_int8_t proto,unsigned int log,unsigned int action) {
	struct cmdRequest req;
    struct KernelResponse rsp;
	// form rule
	struct IPRule rule;
	memset(&rule,'\0',sizeof(rule));

	if(IPstr2IPint(sip,&rule.saddr,&rule.smask)!=0) {
		// rsp.code = ERROR_CODE_WRONG_IP;
		return rsp;
	}
	if(IPstr2IPint(dip,&rule.daddr,&rule.dmask)!=0) {
		//  rsp.code = ERROR_CODE_WRONG_IP;
		return rsp;
	}

	
	rule.sport = sport;
	rule.dport = dport;
	rule.log = log;
	rule.action = action;
	rule.protocol = proto;
	req.tp = REQ_ADDIPRule;

// 	IPint2IPstr(rule.saddr,rule.smask,sip);
// IPint2IPstr(rule.daddr,rule.dmask,dip);


	strncpy(req.ruleName, name, 6);
	strncpy(rule.name, name, 6);
	
	
	req.msg.ipRule = rule;
	
	
	// exchange
	return exMsg(&req, sizeof(req));
}

struct KernelResponse cmdAddRule(void) {
	struct KernelResponse empty;
	char name[7],saddr[25],daddr[25],sport[15],dport[15],protoS[6];
	unsigned short sportMin,sportMax,dportMin,dportMax;
	unsigned int action = NF_DROP, log = 1, proto, i;
	// empty.code = ERROR_CODE_EXIT;
	

	// 规则名
	printf("Please input the rule name : ");
	scanf("%s",name);
	if(strlen(name) == 0 || strlen(name)>6) {
		printf("The name is too long or too short.\n");
		return empty;	
	}
	// 源IP
	printf("Please input the src ip [like 192.168.0.1/24]: ");
	scanf("%s",saddr);
	// 源端口
	printf("Please input src port range : ");
	scanf("%s",sport);


	if(strcmp(sport, "any") == 0||strcmp(sport, "0") == 0) {
		sportMin = 0,sportMax = 0xFFFFu;
	} else {
		sscanf(sport,"%hu-%hu",&sportMin,&sportMax);
	}

	if(sportMin > sportMax) {
		printf("Min > Max. Error.\n");
		return empty;
	}

	// 目的IP
	printf("Please input the dst ip and the dst mask: ");
	scanf("%s",daddr);
	// 目的端口
	printf("Please input dst port range : ");
	scanf("%s",dport);
	if(strcmp(dport, "any") == 0||strcmp(dport, "0") == 0) {
		dportMin = 0,dportMax = 0xFFFFu;
	} else {
		sscanf(dport,"%hu-%hu",&dportMin,&dportMax);
	}
	// if(dportMin > dportMax) {
	// 	printf("Min > Max. Error.\n");
	// 	return empty;
	// }

	// 协议
	printf("Please input the protocol name[TCP/UDP/ICMP/IP]: ");
	scanf("%s",protoS);
	if(strcmp(protoS,"TCP")==0||strcmp(protoS,"tcp")==0)
		proto = IPPROTO_TCP;
	else if(strcmp(protoS,"UDP")==0||strcmp(protoS,"udp")==0)
		proto = IPPROTO_UDP;
	else if(strcmp(protoS,"ICMP")==0||strcmp(protoS,"icmp")==0)
		proto = IPPROTO_ICMP;
	else if(strcmp(protoS,"any")==0||strcmp(protoS,"ip")==0||strcmp(protoS,"IP")==0)
		proto = IPPROTO_IP;
	else {
		printf("Input error!\n");
		return empty;
	}
	// 动作
	printf("Please select the action[1 for accept,0 for drop]: ");
	scanf("%u",&action);
	
	return addFilterRule(name,saddr,daddr,
		(((unsigned int)sportMin << 16) | (((unsigned int)sportMax) & 0xFFFFu)),
		(((unsigned int)dportMin << 16) | (((unsigned int)dportMax) & 0xFFFFu)),proto,log,action);
}





struct KernelResponse getAllFilterRules(void) {
	struct cmdRequest req;
	// exchange msg
	req.tp = REQ_GETAllIPRules;
	return exMsg(&req, sizeof(req));
}

struct KernelResponse delFilterRule(char *name,int len) {
	struct cmdRequest req;
	// form request
	req.tp = REQ_DELIPRule;
	memset(req.ruleName, '\0', 6);
	strncpy(req.ruleName, name, len);
	
	// exchange
	return exMsg(&req, sizeof(req));
}

int showOneRule(struct IPRule rule) {
	char saddr[25],daddr[25],sport[13],dport[13],proto[6],action[8],log[5];
	// ip
	IPint2IPstr(rule.saddr,rule.smask,saddr);
	IPint2IPstr(rule.daddr,rule.dmask,daddr);
	// port
	if(rule.sport == 0xFFFFu)
		strcpy(sport, "any");
	else if((rule.sport >> 16) == (rule.sport & 0xFFFFu))
		sprintf(sport, "only %u", (rule.sport >> 16));
	else
		sprintf(sport, "%u~%u", (rule.sport >> 16), (rule.sport & 0xFFFFu));
	if(rule.dport == 0xFFFFu)
		strcpy(dport, "any");
	else if((rule.dport >> 16) == (rule.dport & 0xFFFFu))
		sprintf(dport, "only %u", (rule.dport >> 16));
	else
		sprintf(dport, "%u~%u", (rule.dport >> 16), (rule.dport & 0xFFFFu));
	// action
	if(rule.action == NF_ACCEPT) {
		sprintf(action, "accept");
	} else if(rule.action == NF_DROP) {
		sprintf(action, "drop");
	} else {
		sprintf(action, "other");
	}
	// protocol
	if(rule.protocol == IPPROTO_TCP) {
		sprintf(proto, "TCP");
	} else if(rule.protocol == IPPROTO_UDP) {
		sprintf(proto, "UDP");
	} else if(rule.protocol == IPPROTO_ICMP) {
		sprintf(proto, "ICMP");
	} else if(rule.protocol == IPPROTO_IP) {
		sprintf(proto, "IP");
	} else {
		sprintf(proto, "other");
	}
	// log
	if(rule.log) {
		sprintf(log, "yes");
	} else {
		sprintf(log, "no");
	}
	// print
	printf("| %-*s | %-18s | %-18s | %-11s | %-11s | %-8s | %-6s | %-3s |\n", MAXRuleNameLen,
	rule.name, saddr, daddr, sport, dport, proto, action, log);
	printLine();
}

int showRules(struct IPRule *rules, int len) {
	int i;
	if(len == 0) {
		printf("No rules now.\n");
		return 0;
	}
	//printf("rule num: %d\n", len);
	printLine();
	printf("| %-*s | %-18s | %-18s | %-11s | %-11s | %-8s | %-6s | %-3s |\n", MAXRuleNameLen,
	 "Rule Name", "src IP", "dst IP", "src Port", "dst Port", "Protocol", "Action", "Log");
	printLine();
	for(i = 0; i < len; i++) {
		showOneRule(rules[i]);
	}
	return 0;
}
struct KernelResponse changeDefault(int df)
{

	struct cmdRequest req;
	// exchange msg
	req.tp = REQ_SETdefault;
	req.msg.defaultAction=df;
	return exMsg(&req, sizeof(req));



}